package cluster_node.scheduler.service;

import cluster_node.models.GlobalVar;
import cluster_node.scheduler.job.UploadJob;
import cluster_node.scheduler.type_config.TypeDeviceUploadHelper;
import org.eclipse.leshan.server.californium.LeshanServer;
import org.eclipse.leshan.server.registration.Registration;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.util.Pool;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class UploadScheduleService {

    private final static Logger LOG = LoggerFactory.getLogger(UploadScheduleService.class);

    private Scheduler scheduler;
    private Map<String, String> typeRegistrationMap;
    private TypeHandlerService typeHandlerService;
    private LeshanServer server;
    private Pool<Jedis> jedisPool;

    public UploadScheduleService(LeshanServer server, Pool<Jedis> jedisPool) {
        this.typeRegistrationMap = new ConcurrentHashMap<>();
        this.typeHandlerService = TypeHandlerService.getInstance();
        this.server = server;
        this.jedisPool = jedisPool;
        try {
            this.scheduler = StdSchedulerFactory.getDefaultScheduler();
            this.scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void register(String type, Registration registration) {
        if (isRegistrationExist(registration)) return;

        typeRegistrationMap.put(registration.getEndpoint(), type);

        TypeDeviceUploadHelper uploadHelper = typeHandlerService.getHelper(type);
        JobDetail jobDetail = createJob(type, server, uploadHelper, registration, jedisPool);

        try {
            scheduler.scheduleJob(jobDetail, createTrigger(GlobalVar.interval));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void deregister(Registration registration) {
        String type = typeRegistrationMap.get(registration.getEndpoint());

        JobKey key = JobKey.jobKey(registration.getEndpoint(), type);
        try {
            this.scheduler.interrupt(key);
            this.scheduler.deleteJob(key);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

        typeRegistrationMap.remove(registration.getEndpoint());
    }


    private boolean isRegistrationExist(Registration registration) {
        return typeRegistrationMap.containsKey(registration.getEndpoint());
    }

    private JobDetail createJob(String type, LeshanServer server, TypeDeviceUploadHelper helper,
                                Registration registration, Pool<Jedis> jedisPool) {
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("server", server);
        jobDataMap.put("helper", helper);
        jobDataMap.put("registration", registration);
        jobDataMap.put("jedisPool", jedisPool);

        return JobBuilder.newJob(UploadJob.class)
                .setJobData(jobDataMap)
                .withIdentity(type, registration.getEndpoint())
                .build();
    }

    private Trigger createTrigger(int interval) {
        return TriggerBuilder.newTrigger()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .repeatForever()
                        .withIntervalInSeconds(interval))
                .startNow()
                .build();
    }
}
